package com.bestv.search.engine.connection.impl;

import com.bestv.search.engine.connection.IConnection;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;

public class HttpClientConnection implements IConnection {

    private final Log log = LogFactory.getLog(HttpClientConnection.class);

    private HttpClient client;

    private PostMethod method;

    public HttpClientConnection() {
        this.client = new HttpClient();
    }

    public HttpClient getClient() {
        return client;
    }

    public void setClient(HttpClient client) {
        this.client = client;
    }

    public PostMethod getMethod() {
        return method;
    }

    public void setMethod(PostMethod method) {
        this.method = method;
    }

    public void connect(URL url) {
        method = new PostMethod(url.toString());
    }

    public void connect(String url) {
        method = new PostMethod(url);
    }

    private void executeMethod(byte[] out, int connectTimeout, int readTimeout) {
        try {
            RequestEntity entity = new ByteArrayRequestEntity(out);
            method.setRequestEntity(entity);
            method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                    new DefaultHttpMethodRetryHandler(0, false));
            method.setRequestHeader("Connection", "close");
            client.getHttpConnectionManager().getParams()
                    .setConnectionTimeout(connectTimeout);
            client.getHttpConnectionManager().getParams()
                    .setSoTimeout(readTimeout);

            client.executeMethod(method);
        } catch (UnsupportedEncodingException e) {
            if (log.isErrorEnabled())
                log.error(e.getMessage());
        } catch (IOException e) {
            if (log.isErrorEnabled())
                log.error(e.getMessage());
        }
    }

    private void executeMethod(NameValuePair[] pairs, int connectTimeout,
                               int readTimeout) {
        try {
            method.setRequestBody(pairs);
            method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                    new DefaultHttpMethodRetryHandler(0, false));
            method.setRequestHeader("Connection", "close");
            client.getHttpConnectionManager().getParams()
                    .setConnectionTimeout(connectTimeout);
            client.getHttpConnectionManager().getParams()
                    .setSoTimeout(readTimeout);

            client.executeMethod(method);
        } catch (UnsupportedEncodingException e) {
            if (log.isErrorEnabled())
                log.error(e.getMessage());
        } catch (IOException e) {
            if (log.isErrorEnabled())
                log.error(e.getMessage());
        }
    }

    public InputStream request(byte[] out) {
        executeMethod(out, 500, 1000);
        try {
            return method.getResponseBodyAsStream();
        } catch (IOException e) {
            if (log.isErrorEnabled())
                log.error(e.getMessage());
        }
        return null;
    }

    public InputStream request(byte[] out, int connectTimeout, int readTimeout) {
        executeMethod(out, connectTimeout, readTimeout);
        try {
            return method.getResponseBodyAsStream();
        } catch (IOException e) {
            if (log.isErrorEnabled())
                log.error(e.getMessage());
        }
        return null;
    }

    public InputStream request(String out) {
        return request(out.getBytes());
    }

    public InputStream request(String out, int connectTimeout, int readTimeout) {
        return request(out.getBytes(), connectTimeout, readTimeout);
    }

    @Override
    public InputStream request(NameValuePair[] pairs, int connectTimeout,
                               int readTimeout) {
        executeMethod(pairs, connectTimeout, readTimeout);
        try {
            return method.getResponseBodyAsStream();
        } catch (IOException e) {
            if (log.isErrorEnabled())
                log.error(e.getMessage());
        }
        return null;
    }

    public String requestStrResult(byte[] out) {
        executeMethod(out, 500, 1000);
        try {
            return method.getResponseBodyAsString();
        } catch (IOException e) {
            if (log.isErrorEnabled())
                log.error(e.getMessage());
        }
        return null;
    }

    public String requestStrResult(String out) {
        return requestStrResult(out.getBytes());
    }

    public void release() {
        method.releaseConnection();
    }
}
